package dparish.client.activity;


import com.google.gwt.activity.shared.AbstractActivity;
import com.google.gwt.place.shared.PlaceController;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;

import dparish.client.places.StudentListPlace;
import dparish.client.proxy.StudentProxy;
import dparish.client.rf.StudentRequest;
import dparish.client.view.StudentView;

/**
 * You don't want this to be a singleton.  You need to pass in a RequestContext but it is VERY important that you don't reuse that context
 * or you will get errors such as:
 * Attempting to edit an EntityProxy previously edited by another RequestContext
 * or:
 * The AutoBean has been frozen
 * @author dparish
 *
 */
public class StudentActivity extends AbstractActivity implements StudentView.Presenter<StudentProxy> {
	
	private StudentView view;
	private StudentProxy student = null;
	private StudentRequest studentRequest;
	private PlaceController placeController = null;
	private Provider<StudentRequest> studentRequestProvider;

	@Inject
	public StudentActivity (StudentView view, StudentRequest request, PlaceController placeController, Provider<StudentRequest> studentRequestProvider) {
		this.view = view;
		studentRequest = request;
		this.placeController = placeController;
		this.studentRequestProvider = studentRequestProvider;
		view.setPresenter(this);
	}
	
	/**
	 * This code saves the student.  This was working just fine for 
	 */
	@Override
	public void onSaveEvent(StudentProxy student) {
		// 	Attempting to edit an EntityProxy previously edited by another RequestContext
		
		Request<Void> saveRequest = studentRequest.store(student);
		saveRequest.fire (new Receiver<Void> () {

			@Override
			public void onSuccess(Void response) {
				view.saveCallback(null);
				placeController.goTo (new StudentListPlace());			
			}
			
			@Override
			public void onFailure (ServerFailure error) {
				view.saveCallback(error.getMessage());
			}
			
		});
	}

	@Override
	public void onCancelEvent() {
		placeController.goTo (new StudentListPlace());			
	}

	public StudentProxy createEmptyStudent() {
		StudentProxy student =studentRequest.create(StudentProxy.class);
		return student;
	}
	
	@Override
	public void setEntity(StudentProxy entity) {
		student = entity;
	}

	@Override
	public StudentProxy getEntity() {
		return student;
	}
	
	private void makeEntityEditable () {
		studentRequest = studentRequestProvider.get();
		student = studentRequest.edit(student);
	}

	/**
	 * If we are passed a full student we have nothing we need to do. If we are passed
	 * a student with only an id, we got this from someone bookmarking the url and need to
	 * look it up.  If we have a null, we need to create an empty student.
	 * 
	 * RequestFactory states with entities is a FREAKIN NIGHTMARE.  
	 * @see <a href="">The autobean has been frozen</a>
	 * 
	 * We try and devine the state of the factory object here so that we don't get one of the may errors.
	 */
	private void getOrBuildStudent () {
		if (student == null) {
			setEntity(createEmptyStudent());
			callRender();
			return;
		}
		if (student.getEmail() != null) {
			// If we got here the user had clicked on the student list. This means
			// the proxy object we have is frozen. To get around that we need to get a new request object
			// and get a new student marked for edit
			makeEntityEditable();
			callRender();
			return;
		}
		if (student.getEmail() == null) {
			// We have an id, but not an email so this is a bookmarked page.
			// Using a new request even if one was passed in since this is the start of a lifecycle
			studentRequest = studentRequestProvider.get();
			Request<StudentProxy> loadRequest = (Request<StudentProxy>) studentRequest.find(student.getId());
			loadRequest.fire(new Receiver<StudentProxy>() {

				@Override
				public void onSuccess(StudentProxy response) {
					student = response;
					makeEntityEditable();
					callRender();
				}
				
				@Override
				public void onFailure(ServerFailure error) {
					Window.alert(error.getMessage());
				}
			});
		}

	}
	
	/**
	 * We need to call view on the render asynchronously so I'll put it in a separate method.
	 */
	private void callRender() {
		view.render();
	}
	
	@Override
	public void start(AcceptsOneWidget container,
			com.google.gwt.event.shared.EventBus eventBus) {
		container.setWidget(view.asWidget());
		getOrBuildStudent();
	}


}
